#! /usr/bin/env python
# -*- coding: utf8 -*-

# Alexandre Coster <acoster@rhrk.uni-kl.de>
# AG DBIS - Technische Universität Kaiserslautern

import gc
import sys
import copy
import math
import random

class transform(object):
    def __init__(self, node, probDistr, algorithms, transforms):
        self.__algorithms = []
        self.__attributes = {}
        self.__cdata      = None
        self.__isRoot     = False

        self.__transforms      = transforms

        if node.find("isRoot") != None:
            self.__isRoot       = True
            self.__copyRate     = float(node.find("copyRate").text.strip())  / 100.0
            self.__untouched    = float(node.find("untouched").text.strip()) / 100.0

            if node.find("selectProbDistr") != None:
                self.__selectProbDistr = probDistr[node.find("selectProbDistr").text.strip()]
                self.__errorRate = None
            else:
                self.__selectProbDistr = None
                self.__errorRate = float(node.find("errorRate").text.strip()) / 100.0


            if node.find("dupRate") != None :
                self.__dupRate   = float(node.find("dupRate").text.strip()) / 100.0
                self.__dupDistro = probDistr[node.find("dupDistr").text]
            else:
                 self.__dupRate = None

        else:
            for i in node.findall("./useAlgorithms/useAlgorithm") + node.findall("./useAlgo"):
                name = i.find("name")
                if i.find("probability") != None:
                    prob = float(i.find("probability").text.strip()) / 100.
                else:
                    prob = float(i.find("useProb").text.strip()) / 100.
                self.__algorithms.append((algorithms[name.text.strip()], prob))

    def __call__(self, nodes=None, node=None, parentMap = None, addIDs = False, root = None, resultAmmount = 1, outFile = None):
        if self.__isRoot:
            toReturn = []
            toCopy   = random.sample(nodes, int(self.__copyRate * len(nodes)))

            for i in range(resultAmmount):
                copies    = [copy.deepcopy(x) for x in toCopy]

                victims   = random.sample(copies, int(len(toCopy) * (1.0 - self.__untouched)))
                toReturn.append(copies)

                for j in victims:
                    tags           = self.__transforms.keys()
                    pMap           = dict(((c,p) for p in j.getiterator() for c in p))
                    allDescendants = filter(lambda x: x.tag in tags, pMap.keys())

                    if self.__selectProbDistr != None:
                        errors = int(self.__selectProbDistr())
                    else:
                        errors = int(math.ceil(self.__errorRate * len(allDescendants)))

                    if errors < 0:
                        errors = 0

                    if outFile != None:
                        outFile.write("%d %d\n" % (len(allDescendants), errors))

                    for i in xrange(errors):
                        if len(allDescendants) == 0:
                            break

                        v = random.choice(allDescendants)
                        if v.tag not in tags:
                            continue

                        returnVal = self.__transforms[v.tag](node=v, parentMap=pMap, root=j)

                        if returnVal == -1:
                            allDescendants.remove(v)
                        elif returnVal == -2:
                            [allDescendants.remove(x) for x in [node] + node.findall(".//*") if x in allDescendants]
                            gc.collect()
            return toReturn
        else:
            while True:
                for i in self.__algorithms:
                    if random.random() < i[1]:
                        return i[0](node, parentMap, root)

    @property
    def isRoot(self):
        return self.__isRoot
